package io.plus.engine.pulse.collections;

import io.plus.engine.pulse.AsynchronousSocketChannelContext;
import io.plus.engine.pulse.Node;
import io.plus.engine.utils.lock.ReadWriteLockMap;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.Lock;

/**
 * 一对一  (ip:port <--> AsynchronousSocketChannelContext)
 */
@Slf4j
public class ClientNodes {
    private ReadWriteLockMap<String, AsynchronousSocketChannelContext> clientNodeToChannelContextMap = new ReadWriteLockMap<>();

    public static String getKey(AsynchronousSocketChannelContext asynchronousSocketChannelContext) {
        Node clientNode = asynchronousSocketChannelContext.getClientNode();
        if (clientNode == null) {
            throw new RuntimeException("client node is null");
        }
        return getKey(clientNode.getIp(), clientNode.getPort());
    }

    public static String getKey(String ip, int port) {
        return ip + ":" + port;
    }

    /**
     * 添加映射
     */
    public void put(AsynchronousSocketChannelContext asynchronousSocketChannelContext) {
        if (asynchronousSocketChannelContext.clientConfiguration.isShortConnection) {
            return;
        }
        try {
            String key = getKey(asynchronousSocketChannelContext);
            clientNodeToChannelContextMap.put(key, asynchronousSocketChannelContext);
        } catch (Exception e) {
            log.error(e.toString(), e);
        }
    }

    /**
     * Removes映射
     */
    public void remove(AsynchronousSocketChannelContext asynchronousSocketChannelContext) {
        if (asynchronousSocketChannelContext.clientConfiguration.isShortConnection) {
            return;
        }
        try {
            String key = getKey(asynchronousSocketChannelContext);
            clientNodeToChannelContextMap.remove(key);
        } catch (Throwable e) {
            log.error(e.toString(), e);
        }
    }

    public AsynchronousSocketChannelContext find(String ip, int port) {
        String key = getKey(ip, port);
        return find(key);
    }

    public AsynchronousSocketChannelContext find(String key) {
        Lock lock = clientNodeToChannelContextMap.getReadLock();
        lock.lock();
        try {
            return clientNodeToChannelContextMap.getObject().get(key);
        } catch (Throwable e) {
            throw e;
        } finally {
            lock.unlock();
        }
    }

    public ReadWriteLockMap<String, AsynchronousSocketChannelContext> getClientNodeToChannelContextMap() {
        return clientNodeToChannelContextMap;
    }
}
